#include<epoll.h>
#include<string.h>
#include<signal.h>
#include<stdlib.h>

static int serv_socket;
static int sockets[MAX_SOCKET_NUM];
static int sockets_cur=0;

/**
 * epoll_init(int port) 初始化
 * 本机回环地址，默认端口22122
 * 
 */
void epoll_init(int port=22122){
    serv_socket = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
    assert(serv_socket > 0);
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(22122);
    bind(serv_socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    listen(serv_socket, 20);
    LOG_MSG("EPOLL INIT FINISHED");
}

/**
 * void epoll_stop(int signo)
 * epoll使用ctrl+C信号停止
 * 
 */
void epoll_stop(int signo){
    LOG_MSG("EPOLL STOP");
    for (int i = 0; i < sockets_cur;i++)
        shutdown(sockets[i], SHUT_RDWR);
    shutdown(serv_socket, SHUT_RDWR);
    exit(0);
}

/**
 * void epoll_work()
 * epoll的工作函数
 * 
 */
void epoll_work(){
    assert(serv_socket> 0);

    //添加监视事件
    epoll_event tmpev, events[MAX_SOCKET_NUM];
    int epfd = epoll_create(MAX_SOCKET_NUM);
    
    tmpev.data.fd = serv_socket;
    tmpev.events = EPOLLIN | EPOLLET;
    epoll_ctl(epfd, EPOLL_CTL_ADD, serv_socket, &tmpev);

    //循环探测：
    signal(SIGINT, epoll_stop);
    signal(SIGTERM, epoll_stop);
    int tmpfd;
    tmpev.events = EPOLLIN|EPOLLRDHUP;
    while (1)
    {
        int fdcnt = epoll_wait(epfd, events, MAX_SOCKET_NUM, -1);
        cout << fdcnt << endl;
        for (int i = 0; i < fdcnt; i++)
        {
            if(events[i].data.fd==serv_socket){
                //检测到新的建立链接
                sockaddr ns_addr;
                socklen_t ns_asize = sizeof(ns_addr);
                int newsocket = accept(serv_socket, &ns_addr, &ns_asize);
                assert(newsocket > 0);

                sockets[sockets_cur++] = newsocket;
                auto buffer_ptr=(rp_buffer *)malloc(sizeof(rp_buffer));
                assert(buffer_ptr != nullptr);
                buffer_ptr->cur_start = 0;
                buffer_ptr->fd = newsocket;
                tmpev.data.ptr = buffer_ptr;
                tmpev.events = EPOLLIN | EPOLLRDHUP;
                epoll_ctl(epfd, EPOLL_CTL_ADD, newsocket, &tmpev);

                socket_regist(buffer_ptr);
                LOG_MSG("new socket add");
            }
            else if(events[i].events&EPOLLRDHUP){
                LOG_MSG("socket break");
                auto ecur = (rp_buffer*)events[i].data.ptr;
                tmpfd = ecur->fd;
                shutdown(tmpfd, SHUT_RDWR);
                epoll_ctl(epfd, EPOLL_CTL_DEL, tmpfd, NULL);
            }
            else if(events[i].events&EPOLLIN){
                //检测到新的输入
                auto tmp = (rp_buffer *)(events[i].data.ptr);
                socket_in(tmp);
            }
            else{
                assert(1 == 0);
            }
        }
    }
}
